/**
 * #info
 *
 *@author   wuwg
 *@createTime   2018/06/03
 *@updateTime   2018/06/03
 *@description  select-tree  component  下拉树组件
 */
/**
 * #item
 *
 * @type         aty-select-tree
 * @cn            下拉树
 * @nameprop    label
 * @menu        表单
 * @stPlugin    true
 * @stContainer false
 * @mixins      [./components/components/form/form-item/form-item.js]
 */
import config from '../../../config/config.js'

// components
import Icon from '../../basic/icon/index.vue'
import Drop from '../../form/select/dropdown/index.vue'
// import FormItem from '../form-item/index.vue'
import tree from '../../navigation/tree/index.vue'
// directives
import clickoutside from '../../../directives/clickoutside'
import TransferDom from '../../../directives/transfer-dom'
// mixins
// import FormItemProps from '../../../mixins/form-item-props.js'
import Emitter from '../../../mixins/emitter.js'
import Locale from '../../../mixins/locale.js'
import formItem from '../form-item/form-item.js'
// prefix
const prefixCls = config.prefix + '-select-tree'
const prefixSelectCls = config.prefix + '-select'
// module
export default {
  name: prefixCls,
  mixins: [Emitter, Locale, /*FormItemProps*/formItem],
  components: { Icon, Drop, /*FormItem,*/ tree },
  directives: { clickoutside, TransferDom },
  /*
   *  model:{
   * prop:'value',  // 属性名
   * event:'change'  //  事件名
   *},
   */
  props: {
    /**
     * #property
     *
     * @name    dropAsync
     * @cn      下拉菜单异步渲染
     * @group   控制
     * @type    boolean
     * @description 下拉菜单是否异步渲染dom，默认false, 如设置为true将无法自动翻译默认值.这时可配合init-data-text手动翻译
     */
    dropAsync: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    value
     * @cn      值
     * @group   基本属性
     * @type    string,array,number
     * @description 最终提供给后端的值
     */
    value: {
      type: [String, Number, Array]
    },
    /**
     * #property
     *
     * @name    data
     * @cn      树的整个数据
     * @group   数据
     * @type    array,object
     * @bind    must
     * @description 树节点的数据，可以是一个对象或者数组。必须字段， {id:'',name:''}
     * 可配字段
     *  children :[]  //  当有子节点时，需要用children字段
     *  disabled :true  //  该节点为禁用状态，不可操作
     *  checked :true  //  当有复选框时，checked控制该节点的选中与否
     *  icon :'url'  //  当有图标时，icon控制其需要显示的图片，为图标路径
     *  open :true  //  控制节点默认是否展开
     *  draggable :true  //  该节点可拖动
     */
    data: {
      type: [Array, Object],
      default () {
        return []
      }
    },
    /**
     * #property
     *
     * @name    requestDataUrl
     * @cn      请求数据的url
     * @group   数据
     * @type    string
     * @description 请求数据的url
     */
    requestDataUrl: {
      type: String
    },
    /**
     * #property
     *
     * @name    requestDataMethod
     * @cn      请求数据的方法
     * @group   数据
     * @type    function
     * @bind    must
     * @description 请求数据的方法；
     * 触发懒加载数据时调用该函数，请注意，回调函数必须执行，否则会一直显示转圈，参数为新加载的数据,参数解释如下：
     *   1.id       当前的节点的id
     *   2.callback function  需要执行的回调函数，参数为新加载的数据（newData）！imporatnt
     *   3.tree    当前的树对象
     *   4.getAllChild 当cascade情况需要同时获取所有后代节点,此时此参数为true
     *     function  requestDataMethod(id,callback,tree){ callback(newData) }
     */
    requestDataMethod: {
      type: Function
    },
    /**
     * #property
     *
     * @name    elementId
     * @cn      select-tree id
     * @group   基本属性
     * @type    string
     * @description 该下拉树上的id
     */
    elementId: {
      type: String
    },
    /**
     * #property
     *
     * @name    transfer
     * @cn      是否将弹层放置于 body 内
     * @group   控制
     * @type    boolean
     * @value  false
     * @description  是否将弹层放置于 body 内，
     *              在 Tabs、带有 fixed 的 Table 列内使用时，建议添加此属性，它将不受父级样式影响，从而达到更好的效果
     */
    transfer: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    placement
     * @cn      下拉框出现的位置
     * @group   样式
     * @type    list
     * @options [top, bottom]
     * @value  bottom
     * @description 该下拉框出现的位置，取值为 ['top', 'bottom']中的其中一个
     */
    placement: {
      validator (value) {
        return Artery.isOneOf(value, ['top', 'bottom'])
      },
      default: 'bottom'
    },
    /**
     * #property
     *
     * @name    placeholder
     * @cn      占位文本
     * @group   基本属性
     * @type    string
     * @description 占位文本
     */
    placeholder: {
      type: String
    },
    /**
     * #property
     *
     * @name    searchPlaceholder
     * @cn      搜索框占位文本
     * @group  基本属性
     * @type    string
     * @version  1.0.0
     * @description 搜索框占位文本
     */
    searchPlaceholder: {
      type: String
    },
    /**
     * #property
     *
     * @name    multiple
     * @cn      是否支持多选
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否支持多选
     */
    multiple: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    disabled
     * @cn      是否禁用
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 该下拉树是否禁用
     */
    disabled: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    clearable
     * @cn      是否有清除按钮
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 该下拉框是否有清除按钮
     */
    clearable: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    canSearch
     * @cn      是否可以搜索定位
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否可以搜索定位，能快速定位到某个节点
     */
    canSearch: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    pinyinSearch
     * @cn      是否支持拼音搜索
     * @group   控制
     * @type	boolean
     * @value  false
     * @description 是否支持拼音搜索,remoteMethod调用的后台需要返回搜索节点的'fullSpell'（汉语拼音全拼）和'simpleSpell'（汉语拼音简拼）数据
     */
    pinyinSearch: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    lazyLoad
     * @cn      是否可以懒加载数据
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否可以懒加载数据
     */
    lazyLoad: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    syncRender
     * @cn      同步渲染
     * @group   控制
     * @type    boolean
     * @value   false
     * @description 当lazyLoad为false的情况此参数有效. syncRender为true时将同步渲染所有树节点, 当节点过多的时候会卡顿.
     * 后台返回的treeNode缺少parentId会导致搜索无法定位, 解决方案有三个(任选其一):
     * 1.lazyLoad=false,syncRender=false, 同时后台返回的treeNode必须包含parentId属性(推荐)
     * 2.remote=true,同时指定remoteMethod, 即自己实现远程搜索功能, 服务端返回的treeNode.id为根节点id到此id的路径, 逗号分隔(推荐)
     * 3.lazyLoad=false,syncRender=true, 同时后台一次性返回整棵树的节点(树节点比较少的情况可以用)
     */
    syncRender: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    autoRequestData
     * @cn      是否自动请求数据
     * @group   控制
     * @type    boolean
     * @value   false
     * @description 是否自动请求数据
     */
    autoRequestData: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    remote
     * @cn      是否使用远程搜索
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否使用远程搜索；默认是远程搜索
     */
    remote: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    remoteMethod
     * @cn      远程搜索的方法
     * @group   控制
     * @type    function
     * @bind    must
     * @description 远程搜索的方法；
     */
    remoteMethod: {
      type: Function
    },
    /**
     * #property
     *
     * @name    icon
     * @cn      图标
     * @group   基本属性
     * @type    icon
     * @value  ios-search-strong
     * @description 搜索框尾部的图标
     */
    icon: {
      type: String,
      default: 'ios-search-strong'
    },
    /**
     * #property
     *
     * @name    cascade
     * @cn      级联选择
     * @group   控制
     * @type    boolean
     * @value   false
     * @version  1.0.0
     * @description 复选框多选时，是否关联子节点选中
     */
    cascade: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    onlyLeaf
     * @cn      只能选叶子节点
     * @group   控制
     * @type    boolean
     * @value   false
     * @version  1.0.2
     * @description 多选适用. true则只有叶子节点可选, 如果同时设置了cascade, 则非叶子节点也会显示checkbox用于级联选择
     */
    onlyLeaf: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    connectParent
     * @cn      关联父级选中
     * @group   控制
     * @type    boolean
     * @value   false
     * @description 复选框多选时，是否关联父级选中
     */
    connectParent: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    showIcon
     * @cn      是否显示图标
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否显示图标
     */
    showIcon: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    searchShowLimit
     * @cn      搜索框显示搜索结果数量限制
     * @group   加载
     * @type    number
     * @bind    must
     * @value   5
     * @description 搜索框显示搜索结果的数量限制,如果调大搜素框会出现滚动条可能影响效果展示
     */
    searchShowLimit: {
      type: Number,
      default: 5
    },
    /**
     * #property
     *
     * @name     initDataText
     * @cn      初始化数据文本
     * @group   数据
     * @type    string,array
     * @description 默认code值对应文本内容, 单选为String, 多选为Array
     *    数据列表是异步的情况下，无法通过code获取到对应的name，所以需要手动设置。
     */
    initDataText: {
      type: [String, Array]
    },
    /**
     * #property
     *
     * @name    maxTagCount
     * @cn      最大显示tag数量
     * @group   样式
     * @type    number
     * @bind    must
     * @version  1.0.0
     * @description 最多显示的tag数量，超出部分默认显示"+2...", 可通过max-tag-placeholder自定义描述, 仅适用于多选
     */
    maxTagCount: {
      type: Number,
      validator (value) {
        return Number.isInteger(value) && value > 0
      },
    },
    /**
     * #property
     *
     * @name    maxTagPlaceholder
     * @cn      tag超出后折叠的显示内容
     * @group   样式
     * @type    string
     * @version  1.0.0
     * @description 自定义tag超出后折叠的显示内容, 可使用模板 例: 共选择{max},超出{overflow}项...
     */
    maxTagPlaceholder: {
      type: String
    },
    /**
     * #property
     *
     * @name    dropdownWidth
     * @cn      下拉框宽度
     * @group   样式
     * @type    number
     * @bind    must
     * @description 如不指定和input保持一致, 指定为0则自适应内容宽度
     */
    dropdownWidth: {
      type: Number
    },
    /**
     * #property
     *
     * @name    popupClass
     * @cn      弹出框样式
     * @type    string
     * @description 可自定义弹框的样式或用于定位该元素
     */
    popupClass: {
      type: String
    },
    /**
     * #property
     *
     * @name    classcodeType
     * @cn      分级代码-类型
     * @group   分级代码
     * @type    string
     * @version   1.0.3
     * @description 分级代码的代码类型
     */
    classcodeType: {
      type: String
    },
    /**
     * #property
     *
     * @name    classcodeCode
     * @cn      分级代码-根节点代码
     * @group   分级代码
     * @type    string
     * @version   1.0.3
     * @description 强制指定类型中的某一个分级代码作为根节点.不指定取类型的默认根.
     */
    classcodeCode: {
      type: String
    },
    /**
     * #property
     *
     * @name    classcodeUrlPrefix
     * @cn      分级代码-url前缀
     * @group   分级代码
     * @type    string
     * @version   1.0.3
     * @description classcode接口url前缀, 如指定末尾必须有'/', 请求最后会拼接上 artery/classcode/{type}
     */
    classcodeUrlPrefix: {
      type: String,
      validator (value) {
        if (value) {
          return value.endsWith('/')
        }
        return true
      },
      default: ''
    },
    /**
     * #property
     *
     * @name    dropDownMaxHeight
     * @cn      下拉数据区域最大高度
     * @group   样式
     * @type    number
     * @value   200
     * @bind    must
     * @description 超出最大高度显示滚动条
     */
    dropDownMaxHeight: {
      type: Number,
      default: 200
    }
  },
  data () {
    return {
      dropLoaded: !this.dropAsync,
      visible: false, // 是否显示下拉框
      prefix: config.prefix, // 前缀
      prefixCls: prefixCls, // 组件前缀
      selectedSingle: {}, // 单选
      selectedMultiple: [], // 多选
      activeId: '',
      checkedIds: [],
      classcodeData: [],
      searchStr: '', // 搜索关键字
      searchData: [], // 搜索下拉框中的数据
      searchDropVisible: false, // 搜索下拉框显示状态
      searchInputWidth: 33, // 搜索输入框的基础宽度
      searchItemFocusIndex: 0 // 上下切换时，搜索项的索引号
    }
  },
  watch: {
    computedData (newValue) {
      // fix: update时候有value这时候需要显示Label
      if (newValue && newValue.length > 0 && this.value) {
        this.updateSelectLabel(newValue)
      }
    },
    // 当前的值
    value (newValue, oldValue) {
      // 设置值
      this.setValue(newValue)
    },
    visible (val) {
      if (val) {
        if (this.dropLoaded) {
          this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
        } else {
          this.dropLoaded = true
        }
      }
      /**
       * #event
       *
       * @name    show-menu
       * @param   status   菜单的显示隐藏状态,Boolean
       * @description  下拉菜单打开,收起时触发
       * @body
       */
      this.$emit('show-menu', val)
    },
    initDataText: {
      handler (value) {
        if (value) {
          this.$nextTick(() => {
            this.ready()
          })
        }
      },
      immediate: true
    },
    classcodeData (newVal) {
      // 当classcodeData改变时，将会刷新显示值，fix-for： value先出现，data后到达，label不显示问题
      this.$nextTick(() => {
        this.ready()
      })
    },
    classcodeType() {
      this.requestClasscodeData()
    },
    classcodeCode() {
      this.requestClasscodeData()
    }
  },
  computed: {
    /*
     * 下拉框容器的类名
     */
    classes () {
      return [
        `${prefixCls}`,
        {
          [`${prefixCls}-visible`]: this.visible,
          [`${prefixCls}-disabled`]: this.disabled,
          [`${prefixCls}-multiple`]: this.multiple,
          [`${prefixCls}-single`]: !this.multiple,
          [`${prefixCls}-show-clear`]: this.showCloseIcon,
          [`${prefixCls}-${this.size}`]: !!this.size
        }
      ].concat(this.formItemClasses)
    },
    dropDownListStyles() {
      return {
        overflowY: 'auto',
        maxHeight: `${this.dropDownMaxHeight}px`
      }
    },
    selectionCls () {
      return {
        [`${prefixCls}-selection`]: !this.autoComplete
      }
    },
    // 下拉框的类名
    dropdownCls () {
      return [
        this.elementId ? prefixCls + this.elementId : '',
        {
          [prefixSelectCls + '-dropdown-transfer']: this.transfer
        }]
    },
    dropdownSearchCls () {
      return [prefixSelectCls + '-dropdown-transfer-search'].concat(this.dropdownCls)
    },
    transitionName () {
      return this.placement === 'bottom' ? 'slide-up' : 'slide-down'
    },
    localePlaceholder () {
      if (this.placeholder === undefined) {
        return this.t('i.select.placeholder')
      } else {
        return this.placeholder
      }
    },
    showPlaceholder () {
      let status = false
      if (this.multiple) {
        if (this.checkedIds.length == 0) {
          status = true
        }
      } else {
        if (!this.activeId) {
          status = true
        }
      }
      return status
    },
    showCloseIcon () {
      return this.clearable && !this.showPlaceholder
    },
    showEllipsis() {
      return this.maxTagCount && this.maxTagCount < this.selectedMultiple.length
    },
    showMaxTagPlaceholder() {
      if (this.maxTagPlaceholder) {
        return this.maxTagPlaceholder
          .replace('{overflow}', this.selectedMultiple.length - this.maxTagCount)
          .replace('{max}', this.selectedMultiple.length)
      } else {
        return '+' + (this.selectedMultiple.length - this.maxTagCount) + '...'
      }
    },
    showSelectedMultiple() {
      if (this.showEllipsis) {
        return this.selectedMultiple.slice(0, this.maxTagCount)
      } else {
        return this.selectedMultiple
      }
    },
    computedData() {
      return this.classcodeType ? this.classcodeData : this.data
    },
    inputStyle () {
      let style = {};
      if (this.multiple) {
        if (this.showPlaceholder) {
          style.width = '100%';
        } else {
          style.width = `${this.searchInputWidth}px`;
        }
      }
      if (this.$refs.reference) {
        let maxWidth = Artery.getStyle(this.$refs.reference, "width")
        if (maxWidth.indexOf('px')) {
          maxWidth = `${parseInt(maxWidth.replace('px', '')) - 24}px`
        }
        style.maxWidth = maxWidth
        style.flexGrow = 1
      }
      return style;
    }
  },
  methods: {
    /** 异步组件加载之后的回调 */
    asyncComponentsLoaded (componentName) {
      switch (componentName) {
        // 这里不采用drop是因为tree的需要单独处理
        case 'tree':
          this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
          break
      }
    },
    getValidateValue () {
      return this.multiple ? this.selectedMultiple.map(o => o.id) : this.selectedSingle.id
    },
    setValue (newValue) {
      // 如果是多选
      if (this.multiple) {
        // 多选框的值
        if (this._delayEmit) {
          this._delayEmit = false
          return
        }
        if (newValue) {
          this.checkedIds = newValue.slice(0)
        } else {
          this.checkedIds = []
        }
      } else {
        // 单选值
        this.activeId = newValue
      }
      // this.dispatchEvent('change', newValue)
    },
    // 隐藏菜单
    hideMenu () {
      this.visible = false
      this.focusIndex = 0
      this.focusIndex = 0;
      this.searchDropVisible = false
      this.searchItemFocusIndex = 0
    },
    // open when focus on Select and press `down` key
    handleFocus () {
      if (!this.visible) {
        this.toggleMenu()
        this.searchDropVisible = false;
      }
    },
    handleClose () {
      this.hideMenu()
    },
    toggleMenu () {
      if (this.disabled) {
        return false
      }
      this.visible = !this.visible
    },
    // 选中树节点
    select (treeNodeData, treeNode, event) {
      /**
       * #event
       *
       * @name    select
       * @param   treeNodeData  当前的树节点数据
       * @param   treeNode      当前的树节点
       * @param   event    event对象
       * @body
       * @description  点击树节点时触发
       */
      this.$emit('select', treeNodeData, treeNode, event)
      if (this.multiple) {
        return // 多选的情况需要点击checkbox, 所以点击树节点不需要走事件
      }
      this.hideMenu()
      // this.dispatchValidateEvent(this.selectedSingle.id)
      this.validate()
    },
    // 清除事件
    clearSelect (event) {
      if (this.showCloseIcon) {
        if(this.multiple){
          const oldValue = this.selectedMultiple.slice(0)
          this.selectedMultiple.splice(0, this.selectedMultiple.length)
          const _model = this.selectedMultiple.map(item => item.id)
          //  数据双向绑定
          this.$emit('input', _model)
          // 触发chang事件
          this.$emit('change', this.selectedMultiple, oldValue, event)
          this.validate()
        }else{
          const oldValue = this.selectedSingle
          this.selectedSingle = {}
          this.searchStr = '';
          this.$emit('input', '')
          // 触发chang事件
          this.$emit('change', this.selectedSingle, oldValue, event)
          // this.dispatchEvent('change', '')
          // this.dispatchValidateEvent('')
          this.validate()
        }
      }
    },
    // 选中节点触发的事件
    check (checked, treeNodeData, treeNode, currentCheckedIds, event) {
      // 先清空数据
      const oldValues = this.selectedMultiple.slice(0)
      /*
       * 不能直接清空, 异步情况,初始化绑定了选项, 这个时候树上还没有这个选项节点的情况下,返回的currentCheckedNodes没有它
       * this.selectedMultiple = [];
       */
      // const allChildren = [treeNodeData]
      // if (this.connectParent) {
      //   this.fillAllChildren(treeNodeData, allChildren)
      // }
      if (checked) {
        // const selectedMultipleIds = this.selectedMultiple.map(item => item.id)
        // for (let i = 0; i < allChildren.length; i++) {
        //   if (!selectedMultipleIds.includes(allChildren[i].id)) {
        //     this.selectedMultiple.push(allChildren[i])
        //   }
        // }
        if (this.canCheck(treeNodeData) && !this.selectedMultiple.map(item => item.id).includes(treeNodeData.id)) {
          this.selectedMultiple.push(treeNodeData)
        }
      } else {
        // for (let i = 0; i < allChildren.length; i++) {
        //   const childData = allChildren[i]
        //   for (let j = 0; j < this.selectedMultiple.length; j++) {
        //     if (this.selectedMultiple[j].id === childData.id) {
        //       this.selectedMultiple.splice(j, 1)
        //       break
        //     }
        //   }
        // }
        if (this.canCheck(treeNodeData)) {
          for (let j = 0; j < this.selectedMultiple.length; j++) {
            if (this.selectedMultiple[j].id === treeNodeData.id) {
              this.selectedMultiple.splice(j, 1)
              break
            }
          }
        }
      }
      if (this.onlyLeaf && this.cascade) {
        this._delayEmit = true
        this.checkedIds = currentCheckedIds
      } else if (oldValues.length !== this.selectedMultiple.length) {
        //  数据双向绑定
        this.$emit('input', currentCheckedIds)
        // 触发chang事件
        this.$emit('change', this.selectedMultiple, oldValues, event)
        // this.dispatchValidateEvent(this.selectedMultiple)
        this.validate()
      }
    },
    canCheck(nodeData) {
      if (this.onlyLeaf) {
        if (nodeData.leaf === undefined) {
          return !nodeData.children || nodeData.children.length == 0
        } else {
          return nodeData.leaf
        }
      }
      return true
    },
    // fillAllChildren (treeNodeData, allChildren) {
    //   if (treeNodeData.children && treeNodeData.children.length) {
    //     for (let i = 0; i < treeNodeData.children.length; i++) {
    //       allChildren.push(treeNodeData.children[i])
    //       this.fillAllChildren(treeNodeData.children[i], allChildren)
    //     }
    //   }
    // },
    // 监听更新事件, 这个只有再动态给select-tree赋值的情况, 间接改变了checkedIds,树更新了选中状态后返回的事件, 所以只有这个时候checkedIds是准的
    watchUpdate (multiple) {
      const _this = this
      const tree = this.$refs.tree
      if (multiple) {
        // 如果多选大于0
        const oldValues = this.selectedMultiple.slice(0)
        if (tree.currentCheckedIds.length > 0) {
          // 不能直接清空, 异步情况,初始化绑定了选项, 这个时候树上还没有这个选项节点的情况下,返回的treeNode没有它
          const selectedMultipleTmp = []
          //  循环key,得出完整数据
          tree.currentCheckedIds.forEach(function (item, index) {
            const nodeData = tree.getTreeNodeData(item)
            if (nodeData) {
              if (_this.canCheck(nodeData)) {
                selectedMultipleTmp.push(nodeData)
              }
            } else { // 有初始化的数据且树是异步并且没有加载出来, 从原来的selectedMultiple中寻找
              let notFount = true
              for (let i = 0; i < _this.selectedMultiple.length; i++) {
                if (_this.selectedMultiple[i].id === item && _this.canCheck(_this.selectedMultiple[i])) {
                  selectedMultipleTmp.push(_this.selectedMultiple[i])
                  notFount = false
                  break
                }
              }
              if (notFount && _this.initDataText && _this.initDataText.length > index) {
                // 没有找到, 说明异步更新了v-model的值, 并且这个值在树中还没有加载出来, 在去initDataText里找找 fixed -> http://code.thunisoft.com/artery/artery-ui/issues/134
                selectedMultipleTmp.push({
                  id: item,
                  name: _this.initDataText[index]
                })
              }
            }
          })
          _this.selectedMultiple = selectedMultipleTmp
        } else {
          this.selectedMultiple = []
        }
        if (this._delayEmit) {
          this.$emit('input', _this.selectedMultiple.map(item => item.id))
          this.$emit('change', this.selectedMultiple, oldValues)
          this.validate()
        }
        // 单选
      } else {
        const oldValue = this.selectedSingle
        // 如果存在，才需要更新
        const activeTreeNodeData = tree.getTreeNodeData(tree.currentActiveId)
        if (activeTreeNodeData) {
          this.selectedSingle = activeTreeNodeData
          this.searchStr = this.selectedSingle.name
          // 不是多选的情况下
          this.$emit('input', this.selectedSingle.id)
          /**
           * #event
           *
           * @name    change
           * @param   newValue 变化后的数据对象
           * @param   oldValue 变化前的数据对象
           * @description  单选时点击节点触发,多选时点击checkbox触发
           * @body
           */
          this.$emit('change', this.selectedSingle, oldValue)
        } else if (this.initDataText) {
          this.selectedSingle = {
            id: this.activeId,
            name: this.initDataText
          }
          this.searchStr = this.initDataText
          // 不是多选的情况下
          this.$emit('input', this.selectedSingle.id)
          this.$emit('change', this.selectedSingle, oldValue)
        } else {
          this.selectedSingle = {}
          this.searchStr = ''
        }
      }
    },
    removeTag (index, event) {
      if (this.disabled) {
        return false
      }
      /*
       * var _model = [];
       * // 判断是不是空数据
       * if( this.currentData.length==0 && this.checkedIds.length>0){
       *     this.checkedIds.splice(index, 1);
       *     _model=this.checkedIds;
       *     this.currentInitDataText.splice(index, 1);
       * }else {
       *     this.selectedMultiple.splice(index, 1);
       *     this.selectedMultiple.forEach((item) => {
       *         _model.push(item.id);
       *     });
       *     if (this.currentInitDataText.length > index) {
       *         this.currentInitDataText.splice(index, 1);
       *     }
       * }
       */
      const oldValue = this.selectedMultiple.slice(0)
      this.selectedMultiple.splice(index, 1)
      const _model = this.selectedMultiple.map(item => item.id)
      //  数据双向绑定
      this.$emit('input', _model)
      // 触发chang事件
      this.$emit('change', this.selectedMultiple, oldValue, event)
      // this.dispatchValidateEvent(this.selectedMultiple)
      this.validate()
    },
    ready () {
      const tree = this.$refs.tree
      if (!tree) { // tree还没有, 一定是dropAsync=true 并且没有点击过下拉
        if (this.multiple) {
          const ids = this.selectedMultiple.map(d => d.id)
          for (let i = 0; i < this.checkedIds.length; i++) {
            const index = ids.indexOf(this.checkedIds[i])
            if (index > -1) {
              this.selectedMultiple.splice(index, 1)
            }
            this.selectedMultiple.push({
              id: this.checkedIds[i],
              name: this.initDataText[i]
            })
          }
        } else {
          this.selectedSingle = {
            id: this.activeId,
            name: this.initDataText
          }
          this.searchStr = this.initDataText
        }
        return
      }
      /*
       * 树加载完后，默认去获取一次值
       * 多选
       */
      if (this.multiple) {
        // 如果多选大于0
        if (tree.currentCheckedIds.length > 0) {
          const selectedMultipleTmp = []
          //  循环key,得出完整数据
          const _this = this
          tree.currentCheckedIds.forEach(function (item, index) {
            const nodeData = tree.getTreeNodeData(item)
            if (nodeData) {
              selectedMultipleTmp.push(nodeData)
            } else if (_this.initDataText && _this.initDataText.length > index) { // 没有的情况再initDataText里找
              selectedMultipleTmp.push({
                id: item,
                name: _this.initDataText[index]
              })
            } else { // 有初始化的数据且树是异步并且没有加载出来, 从原来的selectedMultiple中寻找
              for (let i = 0; i < _this.selectedMultiple.length; i++) {
                if (_this.selectedMultiple[i].id === item) {
                  selectedMultipleTmp.push(_this.selectedMultiple[i])
                  break
                }
              }
            }
          })
          this.selectedMultiple = selectedMultipleTmp
        }
      } else {
        const activeTreeNodeData = tree.getTreeNodeData(tree.currentActiveId)
        // 激活条目
        if (activeTreeNodeData) {
          this.selectedSingle = activeTreeNodeData
          this.searchStr = this.selectedSingle.name
        } else if (this.activeId && this.initDataText) {
          // 这个时候selectedSingle还是空则处理一下initDataText
          this.selectedSingle = {
            id: this.activeId,
            name: this.initDataText
          }
          this.searchStr = this.initDataText
        }
      }
    },
    /**
     * #method
     *
     * @name   getSelectedData
     * @returns  selectedData
     * @description   获取当前选中的数据, 多选为数组, 单选为对象
     */
    getSelectedData () {
      if (this.multiple) {
        return this.selectedMultiple
      } else {
        return this.selectedSingle
      }
    },
    // 更新显示的Label,为了支持异步加载添加
    updateSelectLabel (data) {
      if (this.multiple) {
        const _selectedMultipleTemp = []
        this.value.map(one => {
          const _selected = []
          data.forEach(item => {
            const res = this.findData(one, item)
            if (res) {
              return _selected.push(res)
            }
          })
          if (_selected.length > 0) {
            _selectedMultipleTemp.push(_selected[0])
          }
        })
        this.selectedMultiple = _selectedMultipleTemp
      } else {
        const _selected = []
        data.forEach(item => {
          const res = this.findData(this.value, item)
          if (res) {
            return _selected.push(res)
          }
        })
        if (_selected.length > 0) {
          this.selectedSingle = _selected[0]
        }
      }
    },
    // 递归找数据
    findData (id, data) {
      if (data.id === id && !data.disabled) {
        return data
      } else if (!!data.children && data.children.length > 0) {
        for (const i in data.children) {
          const _data = this.findData(id, data.children[i])
          if (_data !== undefined) {
            return _data
          }
        }
      }
    },
    dataInit(data) {
      /**
       * #event
       *
       * @name    data-init
       * @param   data       数据
       * @body    console.log(data)
       * @version  1.0.3
       * @description  数据首次初始化完成事件
       */
      this.$emit('data-init', data)
    },
    requestClasscodeData() {
      if (this.classcodeType) {
        Artery.ajax.get(`${this.classcodeUrlPrefix}artery/classcode/${this.classcodeType}`, {
          params: {
            code: this.classcodeCode,
            multiple: this.multiple,
            onlyLeaf: this.onlyLeaf
          }
        }).then(result=>{
          this.classcodeData = result
        })
      }
    },
    handleSearchInputClick () {
      // 点击搜索框时，显示树面板
      this.visible = this.visible || true;
    },
    changeSearchInputWidth () {
      this.$nextTick(() => {
        this.searchInputWidth = this.$refs.input.value.length * 12 + 33;
        this.broadcast(config.prefix + '-select-dropdown', 'update-popper');
      })
    },
    handleSearchStrChange () {
      // 搜到值没发生改变，直接return，防止请求过多，浪费资源。
      if (this.oldSearchStr == this.searchStr) {
        return;
      }
      if (this.multiple) {
        this.changeSearchInputWidth()
      }
      // 搜索关键词改变时，将搜索项的索引号重置为0
      this.searchItemFocusIndex = 0
      this.oldSearchStr = this.searchStr
      if (!this.searchStr) {
        this.searchData = []
        this.searchDropVisible = false
        return
      }
      if (this.remote) {
        // 远程请求数据
        this.remoteMethod(this.searchStr, (_data) => {
          // 异步加载 数据返回有延迟 如果此时关键词被清空，则不需要在处理
          if (!this.searchStr) {
            return
          }
          this.setSearchData(_data)
          // 确保树的下拉显示出来
          this.visible = true
          this.searchDropVisible = true
          this.$nextTick(() => {
            if (this.$refs.searchDrop) {
              this.$refs.searchDrop.update()
            }
          })
        })
      } else {
        this.$refs.tree.defaultRemoteMethod(this.searchStr, (_data) => {
          this.setSearchData(_data)
          // 确保树的下拉显示出来
          this.visible = true
          this.searchDropVisible = true
          this.$nextTick(() => {
            if (this.$refs.searchDrop) {
              this.$refs.searchDrop.update()
            }
          })
        })
      }
    },
    setSearchData (_data) {
      // 克隆一份，避免影响原来数据
      _data = Artery.deepCopy(_data)
      // 高亮
      _data = this.patternLightWord(_data)
      // 判断数据的长度
      if(_data.length > this.searchShowLimit){
        _data = _data.slice(0, this.searchShowLimit)
      }
      // 赋值
      this.searchData = _data
    },
    patternLightWord (_data) {
      // 数据匹配度排序：完全匹配在前 + 部分匹配在后
      // 1、全匹配
      var _equalsData = []
      _data = _data.reduce((data, item) => {
        // 如果匹配成功
        if (this.searchStr === item.name || this.pinyinEquals(item)) {
          item.name = String(item.name).replace(this.searchStr, (target) => `<em>${target}</em>`);
          // 添加到数组中
          _equalsData.push(item);
        } else {
          data.push(item)
        }
        return data;
      }, []);

      // 2、部分匹配 正则
      // 正则
      var _matchData = []
      const pattern = new RegExp(this.searchStr.replace(/(\^|\(|\)|\[|\]|\$|\*|\+|\.|\?|\\|\{|\}|\|)/g, '\\$1'), 'igm');
      _matchData = _data.reduce((data, item) => {
        // 如果匹配成功
        if (pattern.test(String(item.name)) || this.pinyinMatch(item)) {
          item.name = String(item.name).replace(pattern, (target) => `<em>${target}</em>`);
          data.push(item);
        }
        return data;
      }, []);
      return _equalsData.concat(_matchData)
    },
    pinyinMatch(item){
      if(this.pinyinSearch && item){
        if(item.fullSpell && item.fullSpell.toLowerCase().indexOf(this.searchStr.toLowerCase()) != -1){
          return true;
        }
        if(item.simpleSpell && item.simpleSpell.toLowerCase().indexOf(this.searchStr.toLowerCase()) != -1){
          return true;
        }
      }
      return false;
    },
    // 拼音全匹配
    pinyinEquals(item){
      if(this.pinyinSearch && item){
        if(item.fullSpell && item.fullSpell.toLowerCase() === this.searchStr.toLowerCase()){
          return true;
        }
        if(item.simpleSpell && item.simpleSpell.toLowerCase() === this.searchStr.toLowerCase()){
          return true;
        }
      }
      return false;
    },
    handleSearchItemClick (item) {
      this.$refs.tree.changeFocusTreeNode(item.id, (treeNode) => {
        if (!treeNode) {
          return;
        }
        // 定位的是叶子节点的话，直接选中
        if (treeNode.treeNodeData.leaf) {
          if (this.multiple) {
            if (!this.selectedMultiple.map(node => node.id).includes(treeNode.treeNodeData.id)) {
              this.selectedMultiple.push(treeNode.treeNodeData)
              this.setValue(this.selectedMultiple.map(node => node.id))
              this.$emit('input', this.selectedMultiple.map(item => item.id))
              this.$emit('change', this.selectedMultiple, this.name)
              this.validate()
            }
          } else {
            if (!this.selectedSingle || this.selectedSingle.id !== treeNode.treeNodeData.id) {
              this.selectedSingle = treeNode.treeNodeData;
              this.searchStr = this.selectedSingle.name;
              this.setValue(this.selectedSingle.id);
              this.$emit('input', this.selectedSingle.id);
              this.$emit('change', this.selectedSingle, this.name)
              this.validate()
            } else {
              this.searchStr = treeNode.treeNodeData.name;
            }
          }
        }
        // 多选时，操作后清空搜索关键词
        if (this.multiple) {
          this.searchStr = ''
        }
        // 隐藏搜索下拉
        this.searchDropVisible = false
      });
    },
    handleSearchInputFocus () {
      // 单选获得焦点时，如果值没变则不触发查询
      if (!this.multiple && this.selectedSingle && this.searchStr === this.selectedSingle.name) {
        return;
      }
      this.oldSearchStr = ''
      this.handleSearchStrChange()
    },
    handleSearchInputBlur () {
      // 单选时 搜索框失去焦点，将值还原回选中的值
      if (!this.multiple) {
        this.searchStr = this.selectedSingle ? this.selectedSingle.name : ''
      }
    },
    delHTMLTag (content) {
      return Artery.delHTMLTag(String(content))
    },
    bindSearchEvent () {
      if (this.canSearch) {
        document.addEventListener('keydown', this.handleKeydown);
      }
    },
    handleKeydown (e) {
      const keyCode = e.keyCode;
      if (this.searchDropVisible) {
        // Esc slide-up
        if (keyCode === 27) {
          e.preventDefault();
          this.hideMenu();
        }
        // next
        if (keyCode === 40) {
          e.preventDefault();
          const next = this.searchItemFocusIndex + 1;
          this.searchItemFocusIndex = (this.searchItemFocusIndex === this.searchData.length) ? 1 : next;
        }
        // prev
        if (keyCode === 38) {
          e.preventDefault();
          const prev = this.searchItemFocusIndex - 1;
          this.searchItemFocusIndex = (this.searchItemFocusIndex <= 1) ? this.searchData.length : prev;
        }
        // enter
        if (keyCode === 13) {
          e.preventDefault();
          if (this.searchData.length > 0) {
            if (this.searchData.length === 1) {
              this.handleSearchItemClick(this.searchData[0])
            } else if (this.searchItemFocusIndex > 0) {
              this.handleSearchItemClick(this.searchData[this.searchItemFocusIndex - 1])
            }
          }
        }
      }
    },
    unbindSearchEvent () {
      if (this.canSearch) {
        document.removeEventListener('keydown', this.handleKeydown);
      }
    }
  },
  created () {
    // 默认设置一次
    this.setValue(this.value)
  },
  beforeMount () {
    this.requestClasscodeData()// 绑定搜索相关事件
    this.bindSearchEvent();
  },
  mounted () {
    this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
    /**
     * #event
     *
     * @name    ready
     * @param   Vue 当前Vue组件对象
     * @description 下拉树组件准备就绪
     * @body
     */
    this.$emit('ready', this)
  },
  beforeDestroy () {
    //解除搜索相关事件
    this.unbindSearchEvent();
  }
}
